package com.futuristik.modes;

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Input.TextInputListener;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Transform;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.OnActionCompleted;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.MoveTo;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.ClickListener;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Image.Scaling;
import com.futuristik.arkitek.ArkitekRenderer;
import com.futuristik.arkitek.Map;
import com.futuristik.objects.ArkitekObject;
import com.futuristik.objects.BrickFloor;
import com.futuristik.objects.Flag;
import com.futuristik.objects.FloorObject;
import com.futuristik.objects.IceFloor;
import com.futuristik.objects.Spikes;
import com.futuristik.objects.Spring;
import com.futuristik.objects.StickyFloor;
import com.futuristik.objects.Flag.FlagType;

public class Creation extends ArkitekMode implements InputProcessor {
	World world;
	Map map;
	OrthographicCamera cam;
	SpriteBatch batch = new SpriteBatch(100);

	InputHandler mapName;
	InputHandler fileName;
	
	ArkitekRenderer renderer;
	ShapeRenderer sr = new ShapeRenderer();
	
	Skin skin;
	Stage ui;
	int state = FREECAMERA;
	int type;

	static int FREECAMERA = 0;
	static int PLACEFLAG = 2;
	static int PLACEFLOOR = 1;
	static int PLACEOBSTACLE = 3;
	static int SCROLLPANEL = 4;
	static int CAMERAMOVE = 5;

	static boolean ADD = false;
	static boolean DELETE = true;
	
	final float panelWidth = (float) (Gdx.graphics.getWidth()/6.0);
	final float panelHeight = Gdx.graphics.getHeight();
	final float leftButtonHeight = (float) (Gdx.graphics.getHeight()/4.0);
	final float rightButtonHeight = (float) (Gdx.graphics.getHeight()/3.0);

	// used as a minimum for dragging to rotate objects
	final float dragThreshold = (float) 0.5;

	Group rightMainPanel;
	Group floorPanel;
	Group flagPanel;
	Group obstaclePanel;

	Group currentPanel;

	//FOR GENERAL PLACING OF OBJECTS/FLOORS/FLAGS/ETC.
	Vector2 startTouch;
	Vector2 endTouch;

	List<ArkitekObject> undoStack = new ArrayList<ArkitekObject>();
	List<Boolean> undoFlags = new ArrayList<Boolean>(); //true if delete
	
	
	List<ArkitekObject> redoStack = new ArrayList<ArkitekObject>();
	List<Boolean> redoFlags = new ArrayList<Boolean>(); //true if delete
	
	
	TextureRegion floorTexture;
	int floorType;

	ArkitekObject tempObject;
	FlagType flag;
	
	ArkitekObject delObject;

	private final Vector2 f = new Vector2();
	private final Vector2 lv = new Vector2();
	
	boolean didUndo;

	public Creation (Game game) {
		super(game);
	}

	public Creation (Game game, Map map){
		super(game);
		this.map = map;
	}

	public class InputHandler implements TextInputListener{

		boolean DONE = false;
		String input;
		String def;
		
		public InputHandler(){
			def = "My Map!";
		}
		public InputHandler(String d){
			def = d;
		}
		
		@Override
		public void canceled() {
			DONE = true;
			input = def;
		}

		@Override
		public void input(String text) {
			DONE = true;
			input = text;
		}
		
		public String get(){
			return input;
		}		
		
		public String getDefault(){
			return def;
		}
		
		public boolean done(){
			return DONE;
		}
	}
	
	@Override
	public void show() {	
		
		world = new World(new Vector2(0, -20), true);

		if(map == null){
			map = new Map();
		}
		
		if(map.name == null){
			mapName = new InputHandler();
			Gdx.input.getTextInput(mapName, "Map Name?", mapName.getDefault());
		}
		
		//map.addRandomObjects(world);
		map.setupWorld(world);

		cam = new OrthographicCamera(Gdx.graphics.getWidth()/8f, Gdx.graphics.getHeight()/8f);
		
		renderer = new ArkitekRenderer(world, cam, map);

		//FLOOR TEMPORARY TEXTURE
		floorTexture = new TextureRegion(new Texture(Gdx.files.internal("data/uiskin.png")), 0, 0, 12, 20);

		ui = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);

		skin = new Skin(Gdx.files.internal("data/uiskin.json"), Gdx.files.internal("data/uiskin.png"));

		Group leftPanel = new Group("leftPanel");
		leftPanel.y = 0;
		leftPanel.x = 0;
		leftPanel.width = panelWidth;
		leftPanel.height = panelHeight;

		Button playButton = new Button(new Image(new TextureRegion(new Texture(Gdx.files.internal("data/Button-Play-icon.png")), 0, 0, 256, 256), Scaling.fit, "playButton"), new ButtonStyle());
		playButton.y = Gdx.graphics.getHeight() - leftButtonHeight;
		playButton.width = panelWidth;
		playButton.height = leftButtonHeight;
		playButton.setClickListener(new ClickListener(){
			@Override
			public void click(Actor actor) {
				for(Flag f : map.getFlags()){
					if(f.type.equals(FlagType.SPAWN)){
						game.setScreen(new Play(game, map, true));
					}
				}
			}
		});
		Button undoButton = new Button("UNDO", skin.getStyle(ButtonStyle.class), "undoButton");
		undoButton.y = Gdx.graphics.getHeight() - 2*leftButtonHeight;
		undoButton.width = panelWidth;
		undoButton.height = leftButtonHeight;
		Button redoButton = new Button("REDO", skin.getStyle(ButtonStyle.class), "redoButton");
		redoButton.y = Gdx.graphics.getHeight() - 3*leftButtonHeight;
		redoButton.width = panelWidth;
		redoButton.height = leftButtonHeight;
		Button deleteButton = new Button("DELETE", skin.getStyle(ButtonStyle.class), "deleteButton");
		deleteButton.width = panelWidth;
		deleteButton.height = leftButtonHeight;

		leftPanel.addActor(playButton);
		leftPanel.addActor(undoButton);
		leftPanel.addActor(redoButton);
		leftPanel.addActor(deleteButton);

		final Group rightMainPanel = new Group("rightMainPanel");
		rightMainPanel.y = 0;
		rightMainPanel.x = 5*panelWidth;
		rightMainPanel.width = panelWidth;
		rightMainPanel.height = panelHeight;

		Button flagButton = new Button("Flag", skin.getStyle(ButtonStyle.class), "flagButton");
		flagButton.y = panelHeight - rightButtonHeight;
		flagButton.height = rightButtonHeight;
		flagButton.width = panelWidth;
		Button floorButton = new Button("Floor", skin.getStyle(ButtonStyle.class), "floorButton");
		floorButton.y = panelHeight - 2*rightButtonHeight;
		floorButton.height = rightButtonHeight;
		floorButton.width = panelWidth;
		Button obstacleButton = new Button("Obstacle", skin.getStyle(ButtonStyle.class), "obstacleButton");
		obstacleButton.height = rightButtonHeight;
		obstacleButton.width = panelWidth;

		rightMainPanel.addActor(flagButton);
		rightMainPanel.addActor(floorButton);
		rightMainPanel.addActor(obstacleButton);		

		/*
		 * FLAG PANEL CREATION
		 */
		final Group flagPanel = new Group("flagPanel");
		flagPanel.y = 0;
		flagPanel.x = 6*panelWidth;
		flagPanel.width = panelWidth;
		flagPanel.height = panelHeight;

		final Button spawnFlagButton = new Button("Spawn", skin.getStyle("toggle", ButtonStyle.class), "spawn");
		spawnFlagButton.y = panelHeight - rightButtonHeight;
		spawnFlagButton.height = rightButtonHeight;
		spawnFlagButton.width = panelWidth;

		final Button checkpointButton = new Button("Checkpoint", skin.getStyle("toggle", ButtonStyle.class), "checkpoint");
		checkpointButton.y = panelHeight - 2*rightButtonHeight;
		checkpointButton.height = rightButtonHeight;
		checkpointButton.width = panelWidth;

		final Button endFlagButton = new Button("End Flag", skin.getStyle("toggle", ButtonStyle.class), "end");
		endFlagButton.y = 0;
		endFlagButton.height = rightButtonHeight;
		endFlagButton.width = panelWidth;

		Button flagBackButton = new Button("Back", skin.getStyle(ButtonStyle.class), "flagBack");
		flagBackButton.y = -rightButtonHeight;
		flagBackButton.height = rightButtonHeight;
		flagBackButton.width = panelWidth;
		//BACK BUTTON HANDLER

		flagBackButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				state = FREECAMERA;
				spawnFlagButton.isChecked = false;
				checkpointButton.isChecked = false;
				endFlagButton.isChecked = false;

				rightMainPanel.touchable = false;

				flagPanel.touchable = false;

				flagPanel.action(MoveTo.$(6*panelWidth, 0, .4f));

				rightMainPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								rightMainPanel.touchable = true;
								currentPanel = rightMainPanel;
							}

						}));
			}
		});

		final Button[] flagButtons = new Button[] {spawnFlagButton, checkpointButton, endFlagButton, flagBackButton};

		flagPanel.addActor(spawnFlagButton);
		flagPanel.addActor(checkpointButton);
		flagPanel.addActor(endFlagButton);
		flagPanel.addActor(flagBackButton);

		/*
		 * END FLAG PANEL CREATION
		 */

		/*
		 * FLOOR PANEL CREATION
		 */

		final Group floorPanel = new Group("floorPanel");
		floorPanel.y = 0;
		floorPanel.x = 6*panelWidth;
		floorPanel.width = panelWidth;
		floorPanel.height = panelHeight;

		final Button floor1Button = new Button("Brick Floor", skin.getStyle("toggle", ButtonStyle.class), "floorButton");
		floor1Button.y = panelHeight - rightButtonHeight;
		floor1Button.height = rightButtonHeight;
		floor1Button.width = panelWidth;

		final Button floor2Button = new Button("Icy Floor", skin.getStyle("toggle", ButtonStyle.class), "floorButton");
		floor2Button.y = panelHeight - 2*rightButtonHeight;
		floor2Button.height = rightButtonHeight;
		floor2Button.width = panelWidth;

		final Button floor3Button = new Button("Sticky Floor", skin.getStyle("toggle", ButtonStyle.class), "floorButton");
		floor3Button.y = 0;
		floor3Button.height = rightButtonHeight;
		floor3Button.width = panelWidth;

		Button floorBackButton = new Button("Back", skin.getStyle(ButtonStyle.class), "flagButton");
		floorBackButton.y = -rightButtonHeight;
		floorBackButton.height = rightButtonHeight;
		floorBackButton.width = panelWidth;
		//BACK BUTTON HANDLER

		floorBackButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				state = FREECAMERA;
				floor1Button.isChecked = false;
				floor2Button.isChecked = false;
				floor3Button.isChecked = false;

				rightMainPanel.touchable = false;

				flagPanel.touchable = false;

				floorPanel.action(MoveTo.$(6*panelWidth, 0, .4f));

				rightMainPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								rightMainPanel.touchable = true;
								currentPanel = rightMainPanel;
							}

						}));
			}
		});


		final Button[] floorButtons = new Button[] {floor1Button, floor2Button, floor3Button, floorBackButton};

		floorPanel.addActor(floor1Button);
		floorPanel.addActor(floor2Button);
		floorPanel.addActor(floorBackButton);
		floorPanel.addActor(floor3Button);

		/*
		 * END FLOOR PANEL CREATION
		 */

		/*
		 * OBSTACLE PANEL CREATION
		 */

		final Group obstaclePanel = new Group("obstaclePanel");
		obstaclePanel.y = 0;
		obstaclePanel.x = 6*panelWidth;
		obstaclePanel.width = panelWidth;
		obstaclePanel.height = panelHeight;

		final Button obstacle1Button = new Button("Spring", skin.getStyle("toggle", ButtonStyle.class), "obstacleButton");
		obstacle1Button.y = panelHeight - rightButtonHeight;
		obstacle1Button.height = rightButtonHeight;
		obstacle1Button.width = panelWidth;

		final Button obstacle2Button = new Button("Spikes", skin.getStyle("toggle", ButtonStyle.class), "obstacleButton");
		obstacle2Button.y = panelHeight - 2*rightButtonHeight;
		obstacle2Button.height = rightButtonHeight;
		obstacle2Button.width = panelWidth;

		Button obstacleBackButton = new Button("Back", skin.getStyle(ButtonStyle.class), "flagButton");
		obstacleBackButton.y = 0;
		obstacleBackButton.height = rightButtonHeight;
		obstacleBackButton.width = panelWidth;
		//BACK BUTTON HANDLER

		obstacleBackButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				state = FREECAMERA;
				obstacle1Button.isChecked = false;
				obstacle2Button.isChecked = false;

				rightMainPanel.touchable = false;

				obstaclePanel.touchable = false;

				obstaclePanel.action(MoveTo.$(6*panelWidth, 0, .4f));

				rightMainPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								rightMainPanel.touchable = true;
								currentPanel = rightMainPanel;
							}

						}));
			}
		});

		final Button[] obstacleButtons = new Button[] {obstacle1Button, obstacle2Button, obstacleBackButton};

		obstaclePanel.addActor(obstacle1Button);
		obstaclePanel.addActor(obstacle2Button);
		obstaclePanel.addActor(obstacleBackButton);

		/*
		 * END OBSTACLE PANEL CREATION
		 */

		/*
		 * CLICK LISTENERS
		 */

		//MAIN
		flagButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				rightMainPanel.touchable = false;
				flagPanel.touchable = false;
				rightMainPanel.action(MoveTo.$(6*panelWidth, 0, .4f));
				flagPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								flagPanel.touchable = true;
								currentPanel = flagPanel;
							}

						}));
			}
		});


		floorButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				rightMainPanel.touchable = false;
				floorPanel.touchable = false;
				rightMainPanel.action(MoveTo.$(6*panelWidth, 0, .4f));
				floorPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								floorPanel.touchable = true;
								currentPanel = floorPanel;
							}

						}));
			}
		});


		obstacleButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				rightMainPanel.touchable = false;
				obstaclePanel.touchable = false;
				rightMainPanel.action(MoveTo.$(6*panelWidth, 0, .4f));
				obstaclePanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
						new OnActionCompleted() {

							@Override
							public void completed(Action action) {
								obstaclePanel.touchable = true;
								currentPanel = obstaclePanel;
							}

						}));
			}
		});

		//FLAG MENU

		spawnFlagButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				buttonHandler((Button) actor, flagButtons, PLACEFLAG, FREECAMERA);
				flag = FlagType.SPAWN;
			}
		});

		checkpointButton.setClickListener(new ClickListener(){
			public void click(Actor actor){
				buttonHandler((Button) actor, flagButtons, PLACEFLAG, FREECAMERA);
				flag = FlagType.CHECKPOINT;
			}
		});

		endFlagButton.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				buttonHandler((Button) actor, flagButtons, PLACEFLAG, FREECAMERA);
				flag = FlagType.END;
			}
		});



		//FLOOR MENU

		floor1Button.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				floorType = 1;
				buttonHandler((Button) actor, floorButtons, PLACEFLOOR, FREECAMERA);
			}
		});

		floor2Button.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				floorType = 2;
				buttonHandler((Button) actor, floorButtons, PLACEFLOOR, FREECAMERA);
			}
		});

		floor3Button.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				floorType = 3;
				buttonHandler((Button) actor, floorButtons, PLACEFLOOR, FREECAMERA);
			}
		});


		//OBSTACLE MENU

		obstacle1Button.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				buttonHandler((Button) actor, obstacleButtons, PLACEOBSTACLE, FREECAMERA);
				type = 0;
			}
		});

		obstacle2Button.setClickListener(new ClickListener(){
			public void click(Actor actor) {
				buttonHandler((Button) actor, obstacleButtons, PLACEOBSTACLE, FREECAMERA);
				type = 1;
			}
		});


		/* Undo */
		undoButton.setClickListener(new ClickListener() {
			public void click(Actor actor) {
				if (undoStack.size() > 0 ) {
					int last = undoStack.size()-1;
					boolean tempBool = undoFlags.remove(last);
					ArkitekObject tempObj = undoStack.remove(last);
					
					if(tempBool) 			//IF TRUE, THEN WE STORED A DELETE SO FLIP AND ADD
						map.objects.add(tempObj);
					else 					//FALSE, so we stored an add
						map.objects.remove(tempObj);
					
					redoFlags.add(!tempBool);
					redoStack.add(tempObj);
					
					didUndo = true;
				}
			}
		});

		/* Redo */
		redoButton.setClickListener(new ClickListener() {
			public void click(Actor actor) {				
				if (redoStack.size() <= 0) {
					return;
				} else if (redoStack.size() > 0 && didUndo) {
					int last = redoStack.size()-1;
					boolean tempBool = redoFlags.remove(last);
					ArkitekObject tempObj = redoStack.remove(last);
					
					if(tempBool) 			//IF TRUE, THEN WE STORED A DELETE SO FLIP AND ADD
						map.objects.add(tempObj);
					else 					//FALSE, so we stored an add
						map.objects.remove(tempObj);
					
					undoFlags.add(!tempBool);
					undoStack.add(tempObj);
				} else {
					didUndo = false;
					redoStack.clear();
					redoFlags.clear();
				}
			}
		});
		
		/* Delete */

		deleteButton.setClickListener(new ClickListener() {
			public void click(Actor actor) {
				if (delObject != null) {
					map.objects.remove(delObject);
					
					undoStack.add(delObject);
					undoFlags.add(DELETE);
					
					didUndo = false;
					redoStack.clear();
					redoFlags.clear();
					
					delObject = null;
				}
			}
		});
		
		/*
		 * GENERAL BACK BUTTON
		 *
			Button backButton = new Button("Back", skin.getStyle(ButtonStyle.class), "flagButton");
			backButton.y = 0;
			backButton.height = rightButtonHeight;
			backButton.width = panelWidth;
			//BACK BUTTON HANDLER

			backButton.setClickListener(new ClickListener(){
				public void click(Actor actor) {
					System.out.println("BACK FROM FLOOR PRESSED");
					rightMainPanel.touchable = false;

					floorPanel.touchable = false;
					flagPanel.touchable = false;
					obstaclePanel.touchable = false;

					flagPanel.action(MoveTo.$(5*panelWidth, -panelHeight, .4f));
					floorPanel.action(MoveTo.$(6*panelWidth, 0, .4f));
					obstaclePanel.action(MoveTo.$(5*panelWidth, panelHeight, .4f));

					rightMainPanel.action(MoveTo.$(5*panelWidth, 0, .4f).setCompletionListener(
							new OnActionCompleted() {

							@Override
							public void completed(Action action) {
							rightMainPanel.touchable = true;
							}

						}));
				}
			});

		 *
		 * END GENERAL BACK BUTTON
		 */

		/*
		 * END CLICK LISTENERS
		 */

		ui.addActor(leftPanel);
		ui.addActor(rightMainPanel);

		ui.addActor(flagPanel);
		ui.addActor(floorPanel);
		ui.addActor(obstaclePanel);

		currentPanel = rightMainPanel;

		Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
		Gdx.input.setInputProcessor(this);	
	}

	public void resize (int width, int height) {
		ui.setViewport(width, height, true);
	}


	@Override
	public void render(float delta) {
		/*
		System.out.println("UndoStack:");
		for(ArkitekObject a : undoStack){
			System.out.println(a);
		}

		System.out.println("RedoStack:");
		for(ArkitekObject a : redoStack){
			System.out.println(a);
		}*/		

		if(mapName != null && mapName.done() && fileName == null){
			fileName = new InputHandler("mymap");
			Gdx.input.getTextInput(fileName, "Saved File Name?", fileName.getDefault());
		}
		
		if(map.name == null && mapName != null){
			map.name = mapName.get();
		}
		if(map.fileName == null && fileName != null){
			map.fileName = fileName.get();
		}
		
		delta = Math.min(0.03f, delta);

		renderer.render(map.getObjects(), delta);

		batch.setProjectionMatrix(cam.combined);
		batch.enableBlending();
		batch.begin();
		if(state == FREECAMERA && delObject != null){
			//RENDER OUTLINE HERE
			sr.begin(ShapeType.Line);

			sr.setProjectionMatrix(cam.combined);
			ArrayList<Fixture> fixlist = delObject.getBody().getFixtureList();
			for (Fixture fixture	: fixlist){
				PolygonShape chain = (PolygonShape)fixture.getShape();
				int vertexCount = chain.getVertexCount();
				Transform transform = delObject.getBody().getTransform();
				Vector2[] vertices = new Vector2[vertexCount];

				for (int i = 0; i < vertices.length; i++)
					vertices[i] = new Vector2();
				
				for (int i = 0; i < vertexCount; i++) {
					chain.getVertex(i, vertices[i]);
					transform.mul(vertices[i]);
				}
				
				sr.setColor(0, 0, 1, 1);
				for (int i = 0; i < vertexCount; i++) {
					Vector2 v = vertices[i];
					if (i == 0) {
						lv.set(v);
						f.set(v);
						continue;
					}
					sr.line(lv.x, lv.y, v.x, v.y);
					lv.set(v);
				}
				sr.line(f.x, f.y, lv.x, lv.y);
			}
			
			sr.end();
			
			
		}
		else if(state == PLACEFLOOR && startTouch != null && endTouch != null){
			Vector2 tempEndTouch = endTouch.cpy();
			tempEndTouch = tempEndTouch.sub(startTouch);
			batch.draw(floorTexture, (startTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x, (Gdx.graphics.getHeight()/2f - startTouch.y)/(8f/cam.zoom) + cam.position.y, 0, 0, tempEndTouch.len()/8, .5f, 1, 1, -tempEndTouch.angle());
		}
		// Render temporary obstacle while it's being rotated
		else if (state == PLACEOBSTACLE && tempObject != null) {
			tempObject.render(batch);
		}

		batch.end();

		ui.draw();
		ui.act(delta);

		if (Gdx.input.isKeyPressed(Keys.ESCAPE)) {
			game.setScreen(new MainMenu(game));
		}
		
		if (Gdx.input.isKeyPressed(Keys.BACK)) {
			game.setScreen(new MainMenu(game));
		}
		
		if (Gdx.input.isKeyPressed(Keys.ESCAPE)) {
			game.setScreen(new MainMenu(game));
		}
		
		if (Gdx.input.isKeyPressed(Keys.BACK)) {
			game.setScreen(new MainMenu(game));
		}
		

		if (Gdx.input.isKeyPressed(Keys.VOLUME_UP)) {
			
			cam.zoom *=1.02;
			if(cam.zoom > (float) 1) cam.zoom = (float) 1;
			System.out.println("VOLUME UP: " + cam.zoom);
			cam.update();
		}
		
		if (Gdx.input.isKeyPressed(Keys.VOLUME_DOWN)) {
			cam.zoom = (float) (cam.zoom - cam.zoom*.02);
			if(cam.zoom < (float) 0.25 ) cam.zoom = (float) 0.25;
			cam.update();
			System.out.println("VOLUME DOWN: " + cam.zoom);
			
			cam.update();
		}
		

	}

	@Override
	public void hide() {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean keyDown(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyUp(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyTyped(char character) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean touchDown(int x, int y, int pointer, int button) {

		//System.out.println("Touch down @ x: " + x + " y: "+ y);

		startTouch = new Vector2(x, y);
		endTouch = startTouch.cpy();		

		if(!ui.touchDown(x, y, pointer, button)){		

			float realX = (startTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x;
			float realY = (Gdx.graphics.getHeight()/2f - startTouch.y)/(8f/cam.zoom) + cam.position.y;
			
			if(state == PLACEOBSTACLE && tempObject == null
				&& Math.abs(realX) < map.getWidth()/2f && Math.abs(realY) < map.getHeight()/2f){
				/*
				 Place the appropriate obstacle type at the click position.
				 This is done during touchDown() so that dragging can be used to rotate
				 the obstacle (just an idea I had as an easy way to use rotation)
				 */
				switch (type) {
				// spring
				case 0: 
					tempObject = new Spring(realX - Spring.width, realY - Spring.height);
					break;
					// spikes	
				case 1:
					tempObject = new Spikes(realX - Spikes.width, realY - Spikes.height);
					break;

				default:
					System.out.println("This obstacle hasn't been implemented yet");
					return false;
				}

				//float w = tempObject.getWidth();
				//float h = tempObject.getHeight();
				
				//tempObject.setPos(tempObject.getX() - w/2f, tempObject.getY() + h/2f);
				
				//map.obstacles.add(tempObject);
			}

		}
		return false;
	}

	@Override
	public boolean touchUp(int x, int y, int pointer, int button) {
		
		float realX = (startTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x;
		float realY = (Gdx.graphics.getHeight()/2f - startTouch.y)/(8f/cam.zoom) + cam.position.y;
		
		//System.out.println("Touch up @ y: "+ y);
		if(!ui.touchUp(x, y, pointer, button)){
			if(state == FREECAMERA && startTouch.dst(endTouch) == 0){
				World tempWorld = new World(new Vector2(-20, 0), true);

				Vector2 worldCoord = new Vector2((startTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x, (Gdx.graphics.getHeight()/2f - startTouch.y)/(8f/cam.zoom) + cam.position.y);
				map.setupWorld(tempWorld);

				delObject = null;
				float minVal = -1;
				for(ArkitekObject v : map.getObjects()){
					Vector2 localCoord = v.getBody().getLocalPoint(worldCoord);
					localCoord.sub(new Vector2(v.width, v.height));
					float dst = localCoord.len();

					if(minVal < 0 || dst < minVal){
						minVal = dst;
						delObject = v;
					}
				}
			}
			else if(state == PLACEFLOOR && startTouch.dst(endTouch) != 0){								
				Vector2 startFloor = new Vector2((startTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x, (Gdx.graphics.getHeight()/2f - startTouch.y)/(8f/cam.zoom) + cam.position.y); 
				Vector2 endFloor = new Vector2((endTouch.x - Gdx.graphics.getWidth()/2f)/(8f/cam.zoom) + cam.position.x, (Gdx.graphics.getHeight()/2f - endTouch.y)/(8f/cam.zoom) + cam.position.y);

				float angle = MathUtils.atan2(startTouch.x - x, startTouch.y - y);

				FloorObject tempFloor = null;

				if(floorType == 1){
					tempFloor = new BrickFloor(endFloor.cpy().add(startFloor).mul(0.5f).x, endFloor.cpy().add(startFloor).mul(0.5f).y, endFloor.dst(startFloor)/2f, angle - MathUtils.PI/2f);
				}
				else if(floorType == 2){
					tempFloor = new IceFloor(endFloor.cpy().add(startFloor).mul(0.5f).x, endFloor.cpy().add(startFloor).mul(0.5f).y, endFloor.dst(startFloor)/2f, angle - MathUtils.PI/2f);
				}
				else if(floorType == 3){
					tempFloor = new StickyFloor(endFloor.cpy().add(startFloor).mul(0.5f).x, endFloor.cpy().add(startFloor).mul(0.5f).y, endFloor.dst(startFloor)/2f, angle - MathUtils.PI/2f);
				}

				map.objects.add(tempFloor);

				// empty out redoObjects after placing something
				didUndo = false;
				redoStack.clear();

				undoStack.add(tempFloor);
				undoFlags.add(ADD);
				
				tempFloor = null;
			}
			else if (state == PLACEOBSTACLE && tempObject != null){
				// now add the new obstacle to the map
				map.objects.add(tempObject);

				// empty out redoObjects after placing something
				didUndo = false;
				redoStack.clear();
				
				undoStack.add(tempObject);
				undoFlags.add(ADD);
				
				tempObject = null;
			}
			else if (state == PLACEFLAG && flag != null
					&& Math.abs(realX) < map.getWidth()/2f && Math.abs(realY) < map.getHeight()/2f){
				if(flag.equals(FlagType.SPAWN) || flag.equals(FlagType.END)){
					for(Flag f : map.getFlags()){
						if(f.type.equals(flag))
							map.objects.remove(f);
					}
				}
				ArkitekObject tempFlag = new Flag(realX - Flag.width, realY - Flag.height, flag);
				
				map.objects.add(tempFlag);

				undoStack.add(tempFlag);
				undoFlags.add(ADD);
				
				// empty out redoObjects after placing something
				didUndo = false;
				redoStack.clear();
			}

		}

		if(state == SCROLLPANEL && startTouch.dst(endTouch) != 0){ //This is outside the previous conditional because the touchUp event could be on the UI or not, it doesn't matter.

			int n = currentPanel.getActors().size();
			float currentY = currentPanel.y;	
			if(currentY > ((n > 3) ? (n-3)*rightButtonHeight : 0)){ // There is a gap below the last item in the panel
				currentPanel.action(MoveTo.$(currentPanel.x, ((n > 3) ? (n-3)*rightButtonHeight : 0), .3f));					
			}
			if(currentY + currentPanel.height < Gdx.graphics.getHeight()){ // There is a gap above the first item in the panel
				currentPanel.action(MoveTo.$(currentPanel.x, Gdx.graphics.getHeight() - currentPanel.height, .3f));
			}

			state = FREECAMERA;
		}

		if(state == CAMERAMOVE)
			state = FREECAMERA;

		return true;
	}

	@Override
	public boolean touchDragged(int x, int y, int pointer) {	
		//System.out.println("Touch dragged @ y: "+ y);
		if(startTouch.x > 5*panelWidth && state != CAMERAMOVE){
			state = SCROLLPANEL;
		}
		if(state == SCROLLPANEL){
			float dy = endTouch.y - y;		
			//System.out.println("x: "+x+" y: "+y+" dy: "+dy);
			currentPanel.action(MoveTo.$(currentPanel.x, currentPanel.y + dy, 0));
			endTouch = new Vector2(x,y);
		}

		if(!ui.touchDragged(x, y, pointer)){
			if(state == FREECAMERA || state == CAMERAMOVE){
				state = CAMERAMOVE;
				Vector2 deltaDrag = new Vector2(x,y);
				deltaDrag.sub(startTouch);
				startTouch = new Vector2(x,y);

				float dx = deltaDrag.x;
				float dy = deltaDrag.y;
				if(cam.position.x-dx > -512 && cam.position.x-dx < 512 && cam.position.y+dy > -512 && cam.position.y+dy < 512)
					cam.translate(-1*0.05f*dx, 0.05f*dy, 0);

				//System.out.println("cam X:"+cam.position.x+" cam Y:"+cam.position.y);
			}
			else if(state == PLACEOBSTACLE && tempObject != null){
				/*
				 * Use the drag x/y and startTouch to rotate the obstacle (experimental)
				 */
				float d = Math.max(Math.abs(startTouch.x - x), Math.abs(startTouch.y - y));
				float angle = (float) Math.atan2(startTouch.x - x, startTouch.y - y);

				if (d >= dragThreshold)
					tempObject.setAngle(angle);
			}
			if(state > 0){
				endTouch = new Vector2(x, y);
			}
		}
		return false;
	}

	@Override
	public boolean touchMoved(int x, int y) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean scrolled(int amount) {
		
		cam.zoom -= amount*.02;
		
		if(cam.zoom < .25f)
			cam.zoom = 0.25f;
		if(cam.zoom > 1.25f)
			cam.zoom = 1.25f;
		
		cam.update();
		
		//System.out.println(amount);
		
		return false;
	}

	private void buttonHandler(Button thisButton, Button[] buttons, int stateOn, int stateOff){
		for(Button v : buttons){
			if(!v.equals(thisButton))
				v.isChecked = false;
		}
		//thisButton.isChecked = !thisButton.isChecked;

		state = thisButton.isChecked ? stateOn : stateOff;
	}

}
